/**
 * \file MemoryPool.h
 * \brief MemoryPool definition class
 * \author Edouard ROGE
 * \date 06 august 2012
 */

#ifndef _MEMORYPOOL_
#define _MEMORYPOOL_

#include <vector>
#include <mutex>
#include "Core/Define/Define.h"
#include "Core/Error/Error.h"

namespace Core
{
	namespace Memory
	{
		/**
		 * \class MemoryPool
		 * \brief Pool of memory with amount of units with fixed size
		 */
		class MemoryPool
		{
		public:
			/**
			 * \fn MemoryPool();
			 * \brief Default constructor
			 */
			MemoryPool();

			/**
			 * \fn ~MemoryPool();
			 * \brief Destructor
			 */
			~MemoryPool();


			/**
			 * \fn MemoryPool(const MemoryPool & _other);
			 * \param _other Memorypool to copy
			 * \brief Copy constructor 
			 */
			MemoryPool(const MemoryPool & _other);

			/**
			 * \fn error BuildPool(uint32 _iUnitNum, uint32 _iUnitSize);
			 * \param _iUnitNum number of unit
			 * \param _iUnitSize size of one unit
			 * \return errOK if the pool is correctly built
			 * \brief build the pool with the actual parameters, size of the pool will be : _iUnitNum x _iUnitSize
			 */
			error BuildPool(uint32 _iUnitNum, uint32 _iUnitSize);

			/**
			 * \fn void * Allocate(uint32 _iSize);
			 * \param _iSize size of needed memory
			 * \return address of allocated memory
			 * \brief allocate memory
			 */
			void * Allocate(uint32 _iSize);

			/**
			 * \fn void Free(void * _ptr);
			 * \param _ptr pointer to free
			 * \brief free memory
			 */
			void Free(void * _ptr);

			/**
			 * \fn uint32 GetPoolSize() const;
			 * \return size of the unit's pool
			 * \brief get the size of a unit from the pool
			 */
			uint32 GetPoolSize() const;

			/**
			 * \fn void GetMemoryLeaks(std::vector<void*> & _res) const;
			 * \param _res vector of pointer addresses to fill
			 * \brief fill the vector in parameter with non-freed memory
			 */
			void GetMemoryLeaks(std::vector<void*> & _res) const;

			/**
			 * \fn void Flush();
			 * \brief flush memory, freed all allocated addresses in the pool. After calling this function, all addresses of the pool are free
			 */
			void Flush();

			/**
			 * \fn bool IsAddressBelongingTo(void * _p) const;
			 * \param _p pointer to test whether it is in the range of the pool adresses
			 * \return true if the pointer belongs to the pool
			 * \brief determines if a pointer belongs to the pool or not
			 */
			bool IsAddressBelongingTo(void * _p) const;

			/**
			 * \fn bool IsAddressFree(void * _ptr) const;
			 * \param _ptr pointer to test whether it is free in the pool
			 * \return true if the pointer is free in the pool
			 * \brief determines if a pointer is free in the pool
			 */
			bool IsAddressFree(void * _ptr) const;

		private:
			/**
			 * \struct Unit
			 * \brief a memory block with pointers to its previous and next blocks
			 */
			struct Unit
			{
				Unit * prev;
				Unit * next;
			};

			/** pointer to all memory allocated for the memory pool*/
			void * m_pMemBlock;

			/** pointer to the allocated memory block */
			Unit * m_pAllocatedMemBlock;

			/** pointer to the first block of free memory */
			Unit * m_pFreeMemBlock;

			/** size of a unit */
			uint32 m_iUnitSize;

			/** size of the whole pool */
			uint32 m_iBlockSize;

			/** Mutex */
			std::mutex m_mutex;
		};
	}
}

#endif // _MEMORYPOOL_
